package com.yf.controller;

import com.alibaba.fastjson.JSONObject;
import com.yf.bean.*;
import com.yf.entity.ExamEntity;
import com.yf.entity.SolveLogEntity;
import com.yf.req.AnswerReq;
import com.yf.service.*;
import com.yf.utils.Pair;
import com.yf.utils.Priority;
import com.yf.utils.UserContext;
import com.yf.utils.Utils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Base64;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Log4j2
@RestController
@RequestMapping(value = "${custom.api-version}")
public class ExamController {
    @Autowired
    ExamService examService;

    @Autowired
    CommonService commonService;

    @Autowired
    RedisService redisService;

    @Autowired
    RecordLogService recordLogService;

    @Autowired
    UserService userService;

    @GetMapping("/")
    public BaseResponse<String> index() {
        return BaseResponse.success("demo-index");
    }

    @PostMapping("/image")
    public BaseResponse<Map<String, Object>> uploadImage(@RequestParam(value = "file[]", required = false) MultipartFile file) {
        return BaseResponse.success(commonService.uploadImage(file));
    }

    @PostMapping("/question/408")
    public BaseResponse<Object> insert408Question(@RequestBody ExamEntity bean) {
        Integer userPriority = UserContext.getUserRole();
        if (!Priority.isEditor(userPriority)) {
            return BaseResponse.of(StatusCode.USER_INVALID_PRIORITY);
        }
        ExamBean exam = bean.getQuestion();
        if (exam == null) {
            return BaseResponse.of(StatusCode.EXAM_BEAN_NULL);
        }
        if (!exam.validate()) {
            return BaseResponse.of(StatusCode.EXAM_INVALID_PARAMS);
        }

        AnswerBean ans = bean.getAnswer();
        if (!ans.validate()) {
            return BaseResponse.of(StatusCode.EXAM_QUS_ANS_INVALID);
        }

        int ret = examService.add408Question(bean);
        if (ret > 0) {
            JSONObject resp = new JSONObject();
            resp.put("pid", exam.getId());
            resp.put("aid", ans.getId());
            return BaseResponse.success(resp);
        }

        if (ret == -1) {
            return BaseResponse.of(StatusCode.EXAM_QUS_INCOMPATIBLE);
        } else if (ret == -2) {
            return BaseResponse.of(StatusCode.EXAM_QUS_ADD_ANS_FAIL);
        }

        return BaseResponse.of(StatusCode.EXAM_INSERT_FAIL);
    }

    @GetMapping("/question")
    public BaseResponse<ExamEntity> getProblemByYear(
            @RequestParam(value = "year", defaultValue = "0") String Year,
            @RequestParam(value = "number", defaultValue = "0") String Number,
            @RequestParam(value = "type", defaultValue = "408") String type) {
        Integer userRole = UserContext.getUserRole();
        if (!Priority.isEditor(userRole)) {
            return BaseResponse.of(StatusCode.USER_PERMISSION_DENY);
        }
        Map<String, String> params = new HashMap<>(3);
        params.put("year", Year);
        params.put("number", Number);
        params.put("type", type);
        return BaseResponse.success(examService.getProblemByYear(params));
    }

    @GetMapping("/question/exist")
    public BaseResponse<Boolean> existQus(
            @RequestParam(value = "year", defaultValue = "0") String Year,
            @RequestParam(value = "number", defaultValue = "0") Integer Number,
            @RequestParam(value = "type", defaultValue = "408") String type) {
        if (Year.equals("0") || Number.equals(0)) {
            return BaseResponse.fail();
        }
        ExamBean bean = new ExamBean();
        bean.setNumber(Number);
        bean.setYear(Year);
        bean.setType(type);
        return BaseResponse.success(examService.existedQus(bean));
    }



    @PostMapping("/question/category")
    public BaseResponse<Map<String, String>> getCategoryInfo(@RequestBody String cate) {
        if (Utils.isNullOrEmpty(cate)) {
            return BaseResponse.fail();
        }
        final Map<String, String> categoryId = redisService.getCategoryId(cate);
        return BaseResponse.success(categoryId);
    }

    @GetMapping("/subject/category")
    public BaseResponse<List<String>> getSubjectCategory(@RequestParam(name = "subject") String subject) {
        final List<String> categories = redisService.getSubjectCateV2(subject);
        List<String> ret = new ArrayList<>(categories.size());
        for (String c : categories) {
            final int cateIdLen = redisService.getSubjectCateLen(subject, c);
            ret.add(String.format("%s,%s", c, cateIdLen));
        }
        return BaseResponse.success(ret);
    }

    @PostMapping("/subject/category")
    public BaseResponse<Map<String, String>> getSubjectCategoryIds(
            @RequestParam(name = "subject") String subject,
            @RequestParam(name = "cate") String cate,
            @RequestParam(name = "start") Integer start,
            @RequestParam(name = "count") Integer count
    ) {
        final List<String> ids = redisService.getSubjectCateIds(subject, cate, start, count);
        if (ids == null) {
            return BaseResponse.success();
        }

        final String s = String.join(".", ids);
        final Map<String, String> ret = Utils.encodeString(s);
        return BaseResponse.success(ret);
    }

    @PostMapping("/question")
    public BaseResponse<List<Map<String, String>>> getTargetQus(@RequestBody List<Long> ids) {
        if (ids == null || ids.size() == 0) {
            return BaseResponse.success(new ArrayList<>(0));
        }
        final Boolean blackUserMark = UserContext.getBlackUserMark();
        List<ExamBean> targetQus;
        List<Map<String, String>> ret;
        if (blackUserMark) {
            targetQus = examService.getFixedQus(ids);
        } else {
            targetQus = examService.getTargetQus(ids);
        }
        ret = new ArrayList<>(targetQus.size());
        for (ExamBean bean: targetQus) {
            ret.add(bean.encode(Utils.getRandInt()));
        }
        return BaseResponse.success(ret);
    }

    @PostMapping("/question/solve/log")
    public BaseResponse<Object> addKillRecords(@RequestBody List<SolveLogBean> records) {
        if (records != null && records.size() > 0) {
            recordLogService.addRecord(records);
        }
        if (records != null && records.size() > 0) {
            final Logger logger = LogManager.getLogger("user.kick.recorder");
            for (SolveLogBean bean: records) {
                logger.info(bean);
            }
        }
        return BaseResponse.success();
    }

    @GetMapping("/question/solve/log")
    public BaseResponse<List<SolveLogEntity>> getUserLog(@RequestParam(name = "token", defaultValue = "") String token) {
        if (Utils.isNullOrEmpty(token)) {
            return BaseResponse.fail();
        }
        final int uid = Utils.decodeUserId(token);
        if (uid > 0) {
            final List<SolveLogEntity> solveLog = recordLogService.getSolveLog((long) uid);
            return BaseResponse.success(solveLog);
        }
        return BaseResponse.fail();
    }

    @GetMapping("/question/solve/detail")
    public BaseResponse<Map<String, String>> getLogDetail(@RequestParam(name = "token", defaultValue = "") String token) {
        if (Utils.isNullOrEmpty(token)) {
            return BaseResponse.fail();
        }
        try {
            Long pid = Long.parseLong(token);
            final ExamBean qus = recordLogService.getQusForLog(pid);
            final Map<String, String> encode = qus.encode(Utils.getRandInt());
            return BaseResponse.success(encode);
        } catch (Exception ignored) {
            //
        }
        return BaseResponse.fail();
    }

    @GetMapping("/question/query/cate")
    public BaseResponse<Map<String, List<String>>> getSubjectCate() {
        List<String> cs = redisService.getSubjectCateV2("CS");
        List<String> os = redisService.getSubjectCateV2("OS");
        List<String> net = redisService.getSubjectCateV2("NET");
        List<String> ccp = redisService.getSubjectCateV2("CCP");
        Map<String,List<String>> ret = new HashMap<>(4);
        ret.put("CS", cs);
        ret.put("OS", os);
        ret.put("NET", net);
        ret.put("CCP", ccp);
        return BaseResponse.success(ret);
    }

    // 根据年份和题号查询题目
    @GetMapping("/question/query")
    public BaseResponse<Map<String, String>> getQusByYearNumber(
            @RequestParam(name = "year", defaultValue = "#") String year,
            @RequestParam(name = "number", defaultValue = "#") String number,
            @RequestParam(name = "type", defaultValue = "408") String type) {
        if (year.equals("#") || number.equals("#")) {
            return BaseResponse.success();
        }
        Map<String, String> params = new HashMap<>(2);
        params.put("year", year);
        params.put("number", number);
        params.put("type", type);
        ExamBean qus = examService.getQusByYearNumber(params);
        Map<String, String> encode = qus.encode(Utils.getRandInt());
        return BaseResponse.success(encode);
    }

    // 获取学科的所有 id
//    @GetMapping("/question/query/subject")
//    public BaseResponse<Map<String, String>> getSubjectQuestion(@RequestParam(name = "subject", defaultValue = "#")String subject) {
//        if (subject.equals("#")) {
//            return BaseResponse.success();
//        }
//        String subjectAllQusID = redisService.getSubjectAllQusID(subject);
//        if (subjectAllQusID != null && subjectAllQusID.length() > 0) {
//            int lk = Utils.getRandInt();
//            byte[] bytes = Utils.mixData(lk, 0, subjectAllQusID.getBytes());
//            String s = Base64.encodeBase64String(bytes);
//            Map<String, String> ret = new HashMap<>(2);
//            ret.put("lk", Utils.encodeInt(lk));
//            ret.put("lc", s);
//            return BaseResponse.success(ret);
//        }
//        return BaseResponse.success();
//    }


    @PostMapping("/question/query/subjects")
    public BaseResponse<List<String>> getMultiSubjectID(@RequestBody List<String> subjects) {
        final int lk = Utils.getRandInt();
        List<String> ret = new ArrayList<>(4);
        ret.add(Utils.encodeInt(lk));
        for (String s: subjects) {
            String allQusID = redisService.getSubjectAllQusIDv2(s);
            System.out.println(allQusID);
            if (!Utils.isNullOrEmpty(allQusID)) {
                String t = s + "_" + allQusID;
                byte[] bytes = Utils.mixData(lk, 0, t.getBytes());
                String encode = Base64.encodeBase64String(bytes);
                ret.add(encode);
            }
        }
        return BaseResponse.success(ret);
    }

    @GetMapping("/question/query/year")
    public BaseResponse<List<Integer>> getQusByYear(
            @RequestParam(name = "year", defaultValue = "#") String year,
            @RequestParam(name = "type", defaultValue = "408") String type) {
        if (year.equals("#")) {
            return BaseResponse.success();
        }

        int Year = 0;
        try {
            Year = Integer.parseInt(year);
            if (Year < 2009 || Year > 2050) {
                return BaseResponse.fail();
            }
        } catch (Exception e) {
            log.error(e);
        }

        if (Year == 0) {
            return BaseResponse.fail();
        }
        Map<String, String> params = new HashMap<>(2);
        params.put("year", String.valueOf(Year));
        params.put("type", type);
        List<Integer> qusIDByYear = examService.getQusIDByYear(params);
        return BaseResponse.success(qusIDByYear);
    }

    // 按照检索标签
    @PostMapping("/question/query/tag")
    public BaseResponse<Map<String, String>> getQusByTag(@RequestBody List<String> tags) {
        if (tags == null || tags.size() == 0) {
            return BaseResponse.success();
        }
        Map<String, String> ret = new HashMap<>(4);
        int lk = Utils.getRandInt();
        ret.put("lk", Utils.encodeInt(lk));
        for (String t: tags) {
            String[] s = t.split("_");
            if (s.length < 2) {
                continue;
            }
//            String subjectCateId = redisService.getSubjectCateId(s[0], s[1]);
            final List<String> ids = redisService.getSubjectCateIds(s[0], s[1], 0, -1);
            byte[] bytes = Utils.mixData(lk, 0, String.join(".", ids));
            ret.put(s[1], Base64.encodeBase64String(bytes));
        }
        return BaseResponse.success(ret);
    }


    @PostMapping("/question/collect")
    public BaseResponse<List<ExamBean>> getQusDescription(@RequestBody List<Integer> ids) {
        if (ids == null || ids.size() == 0) {
            return BaseResponse.success(null);
        }
        return BaseResponse.success(examService.getQusDescription(ids));
    }

    @GetMapping("/question/query/id")
    public BaseResponse<Map<String, String>> getQusById(@RequestParam(name = "pid", defaultValue = "0") Integer pid) {
        if (pid == null || pid == 0) {
            return BaseResponse.fail();
        }
        long id = pid;
        final ExamBean examBean = examService.getQuestionById(id);
        final Map<String, String> encode = examBean.encode(Utils.getRandInt());
        return BaseResponse.success(encode);
    }

    @PostMapping("/answer/add")
    public BaseResponse<Integer> userAddAnswer (@RequestBody AnswerReq req) {
        if (req == null) {
            return BaseResponse.fail();
        }
        final String content = req.getContent();
        if (content == null || content.length() > 2048) {
            return BaseResponse.fail();
        }
        final Integer id = examService.userAddAnswer(content, req.getPid(), req.getAid());
        return BaseResponse.success(id);
    }

    @GetMapping("/answer/del")
    public BaseResponse<Boolean> delUserAnswer (@RequestParam(name = "id", defaultValue = "0") Integer id) {
        if (id == null || id == 0) {
            return BaseResponse.success(true);
        }
        final Boolean ret = examService.delAnswer(id);
        return BaseResponse.success(ret);
    }

    @GetMapping("/answer/query")
    public BaseResponse<AnswerBean> getUserAnswer(@RequestParam(name = "pid", defaultValue = "0") Integer pid) {
        if (pid == null || pid == 0) {
            return BaseResponse.fail();
        }
        final AnswerBean userAnswer = examService.getUserAnswer(pid);
        return BaseResponse.success(userAnswer);
    }
}
